home *** CD-ROM | disk | FTP | other *** search
- /*======================================================================================================
- Auxiliary Data Structures: task and map
- ======================================================================================================*/
- class task { # task structure
- attribute:
- public int* c1, c2; # all cities
- int* tour; # partial tour
- int sum; # partial sum
- }
-
- class map {
- attribute:
- public int size; # matrix size
- int[_,_] dist; # distance matrix
- private int x = 197; # random number seed
- method:
- public gen (int I; int* ?Cities).
- private loop (int I, J).
- }
-
- map {
- gen(size, []).
- gen(I', [I|Cs]) |- loop(I,I+1); gen(I+1, Cs'). # go thru rows
-
- loop(_, size).
- loop(I', J') |- # go thru columns
- x' = (4757 * x + 1) % 32768;
- (int) B' = 1 + ((x / 16) % 256); # random number
- dist[I,J]' = B; # initialize (i,j)
- dist[J,I]' = B; # symmetric (j,i)
- loop(I, J+1).
- }
-
- /*======================================================================================================
- Tsp Specifications
- ======================================================================================================*/
- class Tsp[$done] { # Tsp agent specification
- attribute:
- public Tsp parent = nil; # parent agent
- int[_,_] dist = nil; # distance matrix
- int* best = []; # best tour so far
- int min = 65536; # minimum distance so far
- int qsize = 0; # task count in queue
- task* queue = []; # task queue
- int depth = 2; # search depth before spawn
- protected int count = 34; # queue length threshold
- method:
- public get (task ?Task; int* ?Tour; int ?Sum).
- protected run (task* Queue).
- private spawn (int Count).
- protected explore (int* C1, C2, Tour; int Sum, Depth).
- expand (int* C1, C2, Tour; int Sum, Depth).
- public update (int* Tour; int Sum).
- ask (int* ?Tour; int ?Sum).
- }
-
- Tsp :: TspAgent {
- method:
- public work ().
- }
-
- Tsp :: Root {
- method:
- public do (int[_,_] Dist; int Depth, Count; int* ?Best; int ?Min).
- }
-
- /*======================================================================================================
- Tsp Implementations
- ======================================================================================================*/
- Tsp { # Tsp agent implementation
- get(_,best,min) :- queue == []; $done ! post(1). # queue empty? wakeup!
- get(X,best,min) :- (task*) [X'|queue'] = queue; # dequeue task
- X.sum < min. # task looks ok?
- get(X,best,min) |- get(X',_,_). # no, skip to next task
-
- run([X'|queue']) :- (task) task{C1',C2',T',S'} = X; # extract task properties
- explore(C1,C2,T,S,depth); # do search
- qsize < count; # below threshold?
- run(queue). # work till all finished
- run([_|_]) |- spawn(qsize/count); # over threshold, spawn
- $done ! wait(qsize/count). # wait till all finished
- run([]). # all done!
-
- spawn(0). # no more children!
- spawn(I') |- (task*) [X'|queue'] = queue; # dequeue a task
- (TspAgent) _= TspAgent{self,dist,best,min,1,[X],depth*10};
- spawn(I-1).
-
- explore(_,_,_,S',_) :- min <= S. # bounded cutoff, pruned
- explore([],[],T':[X'|_],S',_) |- # best tour so far
- update(T,S+dist[X,0]). # wrap around for cycle
- explore(C1',C2',T',S',0) |- # level is 0
- qsize' = qsize + 1; # task count in queue
- queue' = [task{C1,C2,T,S}|queue]. # enqueue new task
- explore(C1',C2',T',S',D') |- # level > 0
- expand(C1,C2,T,S,D); # expand cities
- expand(C2,C1,T,S,D). # expand cities
-
- expand([],_,_,_,_). # no more cities
- expand([X'|C1'],C2',T':[Y'|Z'],S',D') |- # expand partial tour
- explore(C1,C2,[X,Y|Z],S+dist[X,Y],D-1); # go down 1 level
- expand(C1,[X|C2],T,S,D). # expand current level
-
- update(_,S') :- min <= S. # new result worst than min?
- update(best',min'). # no, update globals
-
- ask(best,min). # user enquiry on progress
- }
-
- TspAgent {
- ?- Tsp::run(queue); work(). # a working life...
-
- work() :- parent ! update(best, min), # update parent with result
- parent ! get(X':task{_,_,_,_},B',M'); # get task from parent
- Tsp::update(B,M); # update best tour locally
- Tsp::run([X]); work(). # run task
- work(). # ...life ends here
- }
-
- Root {
- do(dist':$[N',N],depth',count',best,min) :-
- best' = []; # no best tour yet
- min' = 65536; # a big number
- qsize' = 0; # singleton queue
- (map) X' = map{N,dist}; # create map object
- X ! gen(0,[C'|Cs']); # generate random weights
- Tsp::run([task{Cs,[],[C],0}]). # start run
- }
-
- /*======================================================================================================
- The End
- ======================================================================================================*/
-